package com.yilin.commons.util;

import com.yilin.commons.exception.BusinessException;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ImageEditUtils {
    static String fromFilePath = "D:\\File\\fromFile\\";
    static String toFilePath = "D:\\File\\toFile\\";

    /**
     * 压缩图片
     * 下载图片
     * 将图片以1.8M大小算出压缩与原图的比例
     * 传入压缩参数比例，设置导出文件路径
     * 将文件转为base64
     */
    public static String picToBase64(String imageUrl) throws Exception {
        String fromFileName = "fromFile" + System.currentTimeMillis() + ".png";
        String toFileName = "toFile" + System.currentTimeMillis() + ".png";
        if (!new File(fromFilePath).exists()) {
            new File(fromFilePath).mkdirs();
        }
        if (!new File(toFilePath).exists()) {
            new File(toFilePath).mkdirs();
        }
        downloadImage(imageUrl, fromFilePath, fromFileName);
        File fromFile = new File(fromFilePath + fromFileName);
        File toFile = new File(toFilePath + toFileName);
        if (getPicSize(fromFile) / 1024F < 1.0 * 1024F) {
            return byteConverterBASE64(fromFile);
        }
        compressPic(fromFile, toFile, 300, 300);
        return byteConverterBASE64(toFile);
    }

    public static void main(String[] args) throws Exception {
        String ss = compressPicForScale("http://117.187.230.142:9000/auth/20221226774CDB018B7049FD87B336240ACDA356.jpg", 500);
        String code = "data:Image/" + "png" + ";base64," + ss;
        Integer len1 = imageSize(ss);

        System.out.println();
    }


    /**
     * 根据指定大小压缩图片
     *
     * @param imagePath   源图片地址（网络地址）
     * @param desFileSize 指定图片大小，单位kb
     * @return 压缩质量后的图片字节数组
     */

    public static String compressPicForScale(String imagePath, long desFileSize) {
        BASE64Encoder encoder = new BASE64Encoder();
        byte[] data = new byte[0];
        try {
            data = onlineImage2byte(imagePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (data.length < desFileSize * 1024) {
            return encoder.encode(data);
        }

        long srcSize = data.length;
        double accuracy = getAccuracy(srcSize / 1024);

        try {
            while (data.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                data = outputStream.toByteArray();

            }
//            System.out.println("【图片压缩】imageId={"+imageId+"} | 图片原大小={"+srcSize / 1024+"}kb | 压缩后大小={"+data.length / 1024+"}kb");
        } catch (Exception e) {
            e.printStackTrace();
        }
//        System.out.println("原始数据后=======" + data.length);
        return encoder.encode(data);
    }


    /**
     * 线上图片转为byte数组
     *
     * @param path
     * @return
     */
    public static byte[] onlineImage2byte(String path) throws IOException {
        byte[] data = null;
        URL url = null;
        InputStream input = null;
        try {
            url = new URL(path);
            HttpURLConnection httpUrl = (HttpURLConnection) url.openConnection();
            httpUrl.connect();
            httpUrl.getInputStream();
            input = httpUrl.getInputStream();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        int numBytesRead = 0;
        while ((numBytesRead = input.read(buf)) != -1) {
            output.write(buf, 0, numBytesRead);
        }
        data = output.toByteArray();
        output.close();
        input.close();
        return data;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }


    //获取文件大小
    public static long getPicSize(File file) {
        return file.length();
    }

    //压缩图片
    public static void compressPic(File fFile, File tFile, int h, int w) {
        try {
            Thumbnails.of(fFile).size(h, w).toFile(tFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //下载图片
    public static void downloadImage(String imageUrl, String filePath, String fileName) throws Exception {
        URL url1 = new URL(imageUrl);
        URLConnection uc = url1.openConnection();
        InputStream inputStream = uc.getInputStream();
        FileOutputStream out = new FileOutputStream(filePath + fileName);
        int j = 0;
        while ((j = inputStream.read()) != -1) {
            out.write(j);
        }
        inputStream.close();
    }

    //字节转BASE64字节码
    public static String byteConverterBASE64(File file) {
        long size = file.length();
        byte[] imageByte = new byte[(int) size];
        FileInputStream fs = null;
        BufferedInputStream bis = null;
        try {
            fs = new FileInputStream(file);
            bis = new BufferedInputStream(fs);
            bis.read(imageByte);
        } catch (FileNotFoundException e) {
            throw new BusinessException("文件" + file.getName() + "不能被找到：" + e.getMessage());
        } catch (IOException e) {
            throw new BusinessException("byte转换BASE64出错：" + e.getMessage());
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    throw new BusinessException("关闭输入流出错：" + e.getMessage());
                }
            }
            if (fs != null) {
                try {
                    fs.close();
                } catch (IOException e) {
                    throw new BusinessException("关闭输入流出错：" + e.getMessage());
                }
            }
        }
        return (new BASE64Encoder()).encode(imageByte);
    }

    /**
     * base64 编码转换为 BufferedImage
     */
    public static BufferedImage base64ToBufferedImage(String base64) {
        if (base64==null) return null;
        if (base64.contains("base64,")) base64 = base64.split("base64,")[1];
        Base64.Decoder decoder = Base64.getDecoder();
        try {
            byte[] bytes1 = decoder.decode(base64);
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
            return ImageIO.read(bais);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * base64 转 File
     * 需包含 前缀
     * */
    public static MultipartFile base64ToMultipartFile (String s) {
        MultipartFile image = null;
        StringBuilder base64 = new StringBuilder("");
        if (s != null && !"".equals(s)) {
            base64.append(s);
            String[] baseStrs = base64.toString().split(",");
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] b = new byte[0];
            try {
                b = decoder.decodeBuffer(baseStrs[1]);
            } catch (IOException e) {
                e.printStackTrace();
            }
            for (int j = 0; j < b.length; ++j) {
                if (b[j] < 0) {
                    b[j] += 256;
                }
            }
            image = new BASE64DecodedMultipartFile(b, baseStrs[0]);
        }
        return image;
    }


    public static Integer imageSize(String image) {
        String str = image.substring(22); // 1.需要计算文件流大小，首先把头部的data:image/png;base64,（注意有逗号）去掉。
        Integer equalIndex = str.indexOf("=");//2.找到等号，把等号也去掉
        if (str.indexOf("=") > 0) {
            str = str.substring(0, equalIndex);
        }
        Integer strLength = str.length();//3.原来的字符流大小，单位为字节
        Integer size = strLength - (strLength / 8) * 2;//4.计算后得到的文件流大小，单位为字节
        return size;
    }

    //BufferedImage 转base64
    public static String getBase64FromImage(BufferedImage img) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            ImageIO.write(img, "png", stream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] bytes = Base64.getEncoder().encode(stream.toByteArray());
        return new String(bytes);
    }


//    public static void main(String[] args) throws Exception {
//        File fFile = new File("D:\\File\\fromFile\\fromFile1621408565468.png");
//        if (getPicSize(fFile)/1024F < 1.8*1024F){
//            System.out.println("压缩跳过");
//           return;
//        }
//        File toFile = new File("D:\\File\\toFile\\压缩后.png");
//        int start = (int) System.currentTimeMillis();   // 开始时间
//        Thumbnails.of(fFile).size(1000,1000).toFile(toFile);
//        int end = (int) System.currentTimeMillis(); // 结束时间
//        int re = end-start; // 但图片生成处理时间
//        System.out.println("图片压缩处理使用了: " + re + "毫秒");
//        System.out.println("输出的图片大小：" + toFile.length()/1024 + "KB");
//    }




    public static class BASE64DecodedMultipartFile implements MultipartFile {

        private final byte[] imgContent;
        private final String header;

        BASE64DecodedMultipartFile(byte[] imgContent, String header) {
            this.imgContent = imgContent;
            this.header = header.split(";")[0];
        }

        @Override
        public String getName() {
            return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
        }

        @Override
        public String getOriginalFilename() {
            return System.currentTimeMillis() + (int) (Math.random() * 10000) + "." + header.split("/")[1];
        }

        @Override
        public String getContentType() {
            return header.split(":")[1];
        }

        @Override
        public boolean isEmpty() {
            return imgContent == null || imgContent.length == 0;
        }

        @Override
        public long getSize() {
            return imgContent.length;
        }

        @Override
        public byte[] getBytes() throws IOException {
            return imgContent;
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(imgContent);
        }

        @Override
        public void transferTo(File dest) throws IOException, IllegalStateException {
            new FileOutputStream(dest).write(imgContent);
        }

    }


    /**
     * 绘制圆角图像
     *
     * @param srcImage 源图像
     * @param angle    圆角大小
     * @return 设置圆角并且缩放后的图像
     */
    public static BufferedImage createRoundImage(BufferedImage srcImage, int angle) {
        BufferedImage result = new BufferedImage(srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = (Graphics2D) result.getGraphics();
        // 绘制圆角图像
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g2.fillRoundRect(0, 0, srcImage.getWidth(), srcImage.getHeight(), angle*2, angle*2);
        g2.setComposite(AlphaComposite.SrcIn);
        g2.drawImage(srcImage, 0, 0, null);
        g2.dispose();

        return result;
    }


    public static int parseHex(final String color) {
        final Matcher mx = Pattern.compile("^#([0-9a-z]{6})$", Pattern.CASE_INSENSITIVE).matcher(color);
        if(!mx.find())
            throw new IllegalArgumentException("invalid color value");
        return Integer.parseInt(mx.group(1), 16);
    }
}